/*
 * Ingenic libsysutils Audio implement.
 *
 * Copyright (C) 2014 Ingenic Semiconductor Co.,Ltd
 * Author: Aeolus <weiqing.yan@ingenic.com>
 */

#ifndef __AUDIO_COMMON_H__
#define __AUDIO_COMMON_H__

#include <stdint.h>
#include <sys/time.h>
#define TIME_OUT 5000 /* timeout is 50000 * 1ms = 5s */
#define SLEEP_TIME 1000 /* usleep, 1ms */

#include <stddef.h>
#define container_of(ptr, type, member) ({\
		const typeof(((type *) 0)->member) *__mptr = (ptr);\
		(type *) ((char *) __mptr - offsetof(type, member));})

struct audio_input_stream {
	void *data;
	unsigned int size;
	void *aec;
	unsigned int aec_size;
	struct  timeval *timestamp;
};

struct audio_ouput_stream {
	void * data;
	unsigned int size;
};

struct audio_parameter {
	unsigned int rate;
	unsigned short format;
	unsigned short channel;
};

struct volume {
	unsigned int channel;
	unsigned int gain;
};

struct alc_gain {
	unsigned int channel;
	unsigned int maxgain;
	unsigned int mingain;
};

//#define DMIC_AI_SET_PARAM           _SIOR ('P', 115, struct audio_parameter)
//#define DMIC_AI_GET_PARAM           _SIOR ('P', 114, struct audio_parameter)
#define AMIC_AI_SET_PARAM           _SIOR ('P', 113, struct audio_parameter)
#define AMIC_AI_GET_PARAM           _SIOR ('P', 112, struct audio_parameter)
#define AMIC_AO_SET_PARAM           _SIOR ('P', 111, struct audio_parameter)
#define AMIC_AO_GET_PARAM           _SIOR ('P', 110, struct audio_parameter)

//#define DMIC_AI_DISABLE_STREAM      _SIOR ('P', 107, int)
//#define DMIC_AI_ENABLE_STREAM       _SIOR ('P', 106, int)
//#define DMIC_AI_GET_STREAM          _SIOR ('P', 105, struct audio_input_stream)
//#define DMIC_ENABLE_AEC             _SIOR ('P', 104, int)
//#define DMIC_DISABLE_AEC            _SIOR ('P', 103, int)
//#define DMIC_SET_AI_VOLUME          _SIOR ('P', 102, int)
#define AMIC_AO_SYNC_STREAM         _SIOR ('P', 101, int)
#define AMIC_AO_CLEAR_STREAM        _SIOR ('P', 100, int)
#define AMIC_AO_SET_STREAM          _SIOR ('P', 99, struct audio_ouput_stream)
#define AMIC_AI_GET_STREAM          _SIOR ('P', 98, struct audio_input_stream)
#define AMIC_AI_DISABLE_STREAM      _SIOR ('P', 97, int)
#define AMIC_AI_ENABLE_STREAM       _SIOR ('P', 96, int)
#define AMIC_AO_DISABLE_STREAM      _SIOR ('P', 95, int)
#define AMIC_AO_ENABLE_STREAM       _SIOR ('P', 94, int)
#define AMIC_ENABLE_AEC             _SIOR ('P', 93, int)
#define AMIC_DISABLE_AEC            _SIOR ('P', 92, int)

#define AMIC_AI_SET_VOLUME          _SIOR ('P', 91, struct volume)
#define AMIC_AI_SET_GAIN            _SIOR ('P', 90, struct volume)
#define AMIC_SPK_SET_VOLUME         _SIOR ('P', 89, struct volume)
#define AMIC_SPK_SET_GAIN           _SIOR ('P', 88, struct volume)
//#define DMIC_AI_SET_VOLUME          _SIOR ('P', 87, int)
#define AMIC_AI_GET_VOLUME          _SIOR ('P', 86, struct volume)
#define AMIC_AI_GET_GAIN            _SIOR ('P', 85, struct volume)
#define AMIC_SPK_GET_VOLUME         _SIOR ('P', 84, struct volume)
#define AMIC_SPK_GET_GAIN           _SIOR ('P', 83, struct volume)
//#define DMIC_AI_GET_VOLUME          _SIOR ('P', 82, int)
#define AMIC_AI_ENABLE_ALC_L        _SIOR ('P', 81, int)
#define AMIC_AI_ENABLE_ALC_R        _SIOR ('P', 80, int)
#define AMIC_AI_HPF_ENABLE          _SIOR ('P', 79, int)
#define AMIC_AI_SET_MUTE            _SIOR ('P', 78, struct channel_mute)
#define AMIC_SPK_SET_MUTE           _SIOR ('P', 77, struct channel_mute)
#define AMIC_AI_SET_ALC_GAIN        _SIOR ('P', 76, struct alc_gain)
#define AMIC_AI_GET_ALC_GAIN        _SIOR ('P', 75, struct alc_gain)


// Audio List
typedef enum {
	MODE_NONE = 0,
	MODE_RECORD, /* Record Mode */
	MODE_PLAY, /* Play Mode */
	MODE_FILTER, /* Filter Mode */
	MODE_AI_CHN,
	MODE_AO_CHN,
	MODE_AENC_CHN,
	MODE_ADEC_CHN,
	MODE_MAX
} AudioListMode;

typedef enum {
	LIST_NOT_USED = 0,
	LIST_USED
} AudioListUsed;

struct AudioList;
typedef struct AudioList AudioList;
struct AudioList {
	AudioList *next;
	AudioListMode mode;
	AudioListUsed used;
	unsigned char *audio_buf;
	int buf_size;
	int64_t timestamp;
	int list_num; /* For Debug */
	AudioList *ref; /* For AI */
};

#define MAX_AO_DEV 0
#define MAX_AO_CHN 0

#define MAX_AI_DEV 1
#define MAX_AI_CHN 0
#define MAX_AI_TRACK 2

#define kSampleRate8kHz     8000

#define GET_FRAME_DEFAULT_WAY 0
#define GET_FRAME_USER_WAY 1

#define GET_NODE_FLAG_ZERO 0
#define GET_NODE_FLAG_ONE 1
#define GET_NODE_FLAG_TWO 2
// Audio In and Out
//#define MAX_AUDIO_DEV 2
//#define MAX_AUDIO_IN_CHN 1
//#define MAX_AUDIO_OUT_CHN 1

/**
 * 音频通道的音量属性结构体.
 */
typedef struct {
	int minVol;				/**< 最小音量值 */
	int maxVol;				/**< 最大音量值 */
	double vol;				/**< 当前音量值对应的系数*/
	int mute;				/**< 静音标志 0:非静音 1:静音 */
} IMPAudioVol;

typedef struct {
	int chnID;
	int enable;
	IMPAudioVol vol;
	IMPAudioIChnParam audioIChnParam;
	AudioList *frameHeadIn;
	AudioList *frameHeadOut;
	IMPAudioFrame audioFrame;
	pthread_mutex_t mutex_chn;

	int ch_disable_done;
	int ch_disable_ref_done;
	pthread_cond_t cond_ai_ch_disable;
	pthread_cond_t cond_ai_ch_disable_ref;
	pthread_cond_t cond_ai_ch_polling;
	int ref_en;
	void *ref_buf;

	void *aec_handle;
	char *aec_buf;
	int ai_internel_aec;

	void *ai_buf;
	double ai_vol_coef;

	int ai_vol;
	int ai_ch_gain;
	int ai_ch_dgain;
	int ai_ch_alc_en;
	int ai_ch_alc_maxgain;
	int ai_ch_alc_mingain;

	int hpf_co_frequency;
	int ai_agc_enable_suppression;
	int ai_hpf_enable_suppression;
	int ai_aec_enable_suppression;
	int ai_ns_enable_suppression;
	int ai_hs_enable_suppression;

	pthread_mutex_t mutex_ai_agc;
	pthread_mutex_t mutex_ai_hpf;
	pthread_mutex_t mutex_ai_aec;
	pthread_mutex_t mutex_ai_ns;
	pthread_mutex_t mutex_ai_hs;

	int user_frmlen;
	int user_ref_frmlen;
	char *ai_tmp_buf;
	char *ai_tmp_refBuf;
	int ai_tmp_size;
	char *copybuf;
	int copybytes;
	char *copyRefbuf;
	int copyRefbytes;

	char getNodeFlag; /*record branch of calling audio_buf_get_data in AI_GetFrame*/
	void *ai_data_address; /*save the struct ai_data adress in AI_GetFrame;*/

} AudioInChn;

typedef struct {
	int chnID;
	int enable;
	int pause;
	IMPAudioVol vol;
	AudioList *frameHeadIn;
	AudioList *frameHeadOut;
	IMPAudioFrame audioFrame;
	IMPAudioOChnState status;
	pthread_mutex_t mutex_chn;

	int pause_done;
	int disable_done;
	void *ao_buf;
	int ao_ch_keep_old_vol;
	double ao_ch_keep_old_vol_coef;
	int ao_ch_keep_old_gain;
	int ao_ch_dgain;
	int sync;
	int cache_en;

	pthread_mutex_t mutex_flush;
	pthread_cond_t  cond_flush;

	int hpf_co_frequency;
	int ao_agc_enable_suppression;
	int ao_hpf_enable_suppression;
	pthread_mutex_t mutex_ao_agc;
	pthread_mutex_t mutex_ao_hpf;

	int ao_tmp_size;
	char *ao_tmp_buf;
	int remainbytes;
	char *remainbuf;

} AudioOutChn;
#if 0
typedef struct {
	int devID;
	int aiEnable;
	int aoEnable;
	pthread_t aiProcess;
	pthread_t aoProcess;

	IMPAudioIOAttr audioIAttr;
	IMPAudioIOAttr audioOAttr;

	AudioInChn audioInChn[MAX_AUDIO_IN_CHN];
	AudioOutChn audioOutChn[MAX_AUDIO_OUT_CHN];
} AudioDev;
#endif
typedef struct {
	int devID;
	int aoEnable;
	int aofd;
	pthread_t aoProcess;
	IMPAudioIOAttr audioOAttr;
	int user_numperfrm;
	int max_buf_size;
	AudioOutChn audioOutChn[MAX_AO_CHN+1];
} AudioOutDev;

typedef struct {
	int devID;
	int aiEnable;
	int aifd;
	pthread_t aiProcess;
	IMPAudioIOAttr audioIAttr;
	int user_numperfrm;		/*numperfrm set by user.*/
	char getFrameWay;		/*the way of get frame;0:defalt way,1:user way*/
	int max_buf_size;
	AudioInChn audioInChn[MAX_AI_CHN+1];
	pthread_mutex_t mutex_dev;
	pthread_cond_t cond_dev;
	void *tmpbuf;
	int tmpbufsize;
	int thread_wait;

} AudioInDev;

#define kSampleRate8kHz     8000

extern AudioList *Audio_Chn_Prefetch_List(AudioList **in, AudioList **out, AudioListUsed used);
extern void Chn_Lock(pthread_mutex_t *mutex);
extern void Chn_UnLock(pthread_mutex_t *mutex);
extern int Audio_Chn_Release_List(AudioList **in, AudioList **out, AudioListUsed used);
extern int Audio_List_Free(AudioList *list);
extern AudioList *Audio_List_Alloc(AudioListMode mode, int max_buf_num);
extern int Audio_Chn_Clear_List(AudioList **in, AudioList **out);
extern void _audio_set_volume(char *src, char *dst, int size, int pcmbit, double exv);
extern int _ai_get_buf_size(void);
extern int _ao_get_buf_size(void);

int init_audioProcess_library(const char *libFileName, void **handle);  //initialize loadlibrary
int deinit_audioProcess_library(void **handle);
int Hpf_Version(char *versionStr, char length);
void Hpf_gen_filter_coefficients(short* coef, int samplerate, int p_rate);

#endif /* __AUDIO_COMMON_H__ */
